package org.asiainfo.common.excel.core;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.merge.AbstractMergeStrategy;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
import org.asiainfo.common.core.utils.reflect.ReflectUtils;
import org.asiainfo.common.excel.annotation.CellMerge;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 基于注解CellMerge 列值重复时，合并单元格策略
 *
 * @author dotor-ww
 */
public class CellMergeStrategy extends AbstractMergeStrategy {

    /**
     * 单元格范围地址
     */
    private final List<CellRangeAddress> cellList;

    /**
     * 是否是标题
     */
    private final Boolean isTitle;

    private int rowIndex;

    public CellMergeStrategy(List<?> list, Boolean isTitle) {
        this.isTitle = isTitle;
        this.rowIndex = isTitle ? 1 : 0;
        this.cellList = handleCellMerge(list, isTitle);
    }

    /**
     * 处理合并数据
     *
     * @param list     数据
     * @param hasTitle 是否合并
     * @return 合并结果
     */
    private List<CellRangeAddress> handleCellMerge(List<?> list, Boolean isTitle) {
        //判断数据是否为空
        if (CollUtil.isEmpty(list)) return CollUtil.newArrayList();
        //获取所有字段并排除serialVersionUID
        Field[] fields = ReflectUtils.getFields(list.get(0).getClass(), field -> !"serialVersionUID".equals(field.getName()));
        List<Field> mergeFields = new ArrayList<>();
        List<Integer> mergeFieldsIndex = new ArrayList<>();
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            if (field.isAnnotationPresent(CellMerge.class)) {
                CellMerge cellMerge = field.getAnnotation(CellMerge.class);
                mergeFields.add(field);
                mergeFieldsIndex.add(cellMerge.index() == -1 ? i : cellMerge.index());

                //是否使用ExcelProperty注解
                if (isTitle) {
                    ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
                    rowIndex = Math.max(rowIndex, excelProperty.value().length);
                }
            }
        }

        //临时map数据
        Map<Field, RepeatCell> map = new HashMap<>();
        for (int i = 0; i < list.size(); i++) {
            for (int j = 0; j < mergeFields.size(); j++) {
                //反射字段
                Field field = mergeFields.get(j);
                //获取字段内容
                Object val = ReflectUtils.invokeGetter(list.get(i), field.getName());
                int colNum = mergeFieldsIndex.get(j);
                //判断是否存在该字段
                if (map.containsKey(field)) {
                    RepeatCell repeatCell = map.get(field);
                    Object cellValue = repeatCell.getCellValue();

                    // 空值跳过不合并
                    if (ObjectUtil.isNull(cellValue) || "".equals(cellValue)) continue;

                    //值不相同
                    if (!cellValue.equals(val)) {
                        if (i - repeatCell.getCellIndex() > 1) {
                            cellList.add(new CellRangeAddress(repeatCell.getCellIndex() + rowIndex, i + rowIndex - 1, colNum, colNum));
                        }
                        map.put(field, new RepeatCell(val, i));
                    } else if (j == 0) {
                        if (i == list.size() - 1) {
                            if (i > repeatCell.getCellIndex()) {
                                cellList.add(new CellRangeAddress(repeatCell.getCellIndex() + rowIndex, i + rowIndex, colNum, colNum));
                            }
                        }
                    } else {
                        // 判断前面的是否合并了
                        RepeatCell firstCell = map.get(mergeFields.get(0));
                        if (repeatCell.getCellIndex() != firstCell.getCellIndex()) {
                            if (i == list.size() - 1) {
                                if (i > repeatCell.getCellIndex()) {
                                    cellList.add(new CellRangeAddress(repeatCell.getCellIndex() + rowIndex, i + rowIndex, colNum, colNum));
                                }
                            } else if (repeatCell.getCellIndex() < firstCell.getCellIndex()) {
                                if (i - repeatCell.getCellIndex() > 1) {
                                    cellList.add(new CellRangeAddress(repeatCell.getCellIndex() + rowIndex, i + rowIndex - 1, colNum, colNum));
                                }
                                map.put(field, new RepeatCell(val, i));
                            }
                        } else if (i == list.size() - 1) {
                            if (i > repeatCell.getCellIndex()) {
                                cellList.add(new CellRangeAddress(repeatCell.getCellIndex() + rowIndex, i + rowIndex, colNum, colNum));
                            }
                        }
                    }
                } else {
                    map.put(field, new RepeatCell(val, i));
                }
            }
        }
        return cellList;
    }

    /**
     * merge
     *
     * @param sheet            Excel 工作表的高级表示形式
     * @param cell             电子表格中一行单元格的高级表示形式
     * @param head             Excel头
     * @param relativeRowIndex 相对行索引
     */
    @Override
    protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
        if (CollUtil.isNotEmpty(cellList)) {
            if (cell.getRowIndex() == rowIndex && cell.getColumnIndex() == 0) {
                for (CellRangeAddress cellAddresses : cellList) {
                    //添加合并的索引
                    sheet.addMergedRegion(cellAddresses);
                }
            }
        }
    }

    /**
     * 重复单元格
     */
    @Data
    @AllArgsConstructor
    static class RepeatCell {

        /**
         * 单元格内容
         */
        private Object cellValue;

        /**
         * 单元格索引
         */
        private int cellIndex;
    }
}
